using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WozLib.WozCommands;
using WozLib.WozObjects;
using WOzTestUI.WozCommands;
using WOzTestUI.WozObjects;
using System.Diagnostics;
using WozLib.UI.Ink;

namespace WOzTestUI
{
  /// <summary>
  /// Interaction logic for ScratchWindow.xaml
  /// </summary>

  public partial class ScratchWindow : System.Windows.Window, IServerObject, IListboxWindow
  {

    // stack of server commands that represent the undo stack
    Stack<WozLib.WozCommands.WozCommand> _UndoStack = new Stack<WozLib.WozCommands.WozCommand>();

    // stack of server commands that represent the redo stack
    Stack<WozLib.WozCommands.WozCommand> _RedoStack = new Stack<WozLib.WozCommands.WozCommand>();

    // list of server commands that represent the entire history of the wizards actions
    List<WozLib.WozCommands.WozCommand> _WizardHistory = new List<WozLib.WozCommands.WozCommand>();

    public WozScreenCollection WozScreens
    {
      get { return _WozScreens; }
      set { _WozScreens = value; }
    } WozScreenCollection _WozScreens;

    public ObjectDataProvider WozScreensProvider
    {
      get { return _WozScreensProvider; }
      set { _WozScreensProvider = value; }
    } private ObjectDataProvider _WozScreensProvider;

    public ListBox ScreensListBox
    {
      get
      {
        return _ScreensListBox;
      }
    }

    public ScratchWindow()
    {
      ServerObjectRegistry.RegisterObject(this);

      WozScreens = new WozScreenCollection();
      WozScreensProvider = new ObjectDataProvider();
      WozScreensProvider.ObjectInstance = WozScreens;

      WozScreen wozScreen1 = new WozScreen();
      ServerObjectRegistry.RegisterObject(wozScreen1);
      wozScreen1.CommandOccured += new SketchPad.CommandOccuredDelegate(WozScreen_CommandOccured);
      wozScreen1.CommandOccuredNoUndoRedo += new SketchPad.CommandOccuredDelegate(wozScreen_CommandOccuredNoUndoRedo);
      wozScreen1.ContinuousCommandOccured += new SketchPad.CommandOccuredDelegate(wozScreen_ContinuousCommandOccured);
      WozScreens.Add(wozScreen1);

      InitializeComponent();

      this.Loaded += new RoutedEventHandler(ScratchWindow_Loaded);

      CommandBinding UndoCommandBinding = new CommandBinding(ApplicationCommands.Undo);
      UndoCommandBinding.Executed += new ExecutedRoutedEventHandler(UndoCommandBinding_Executed);
      UndoCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(UndoCommandBinding_CanExecute);
      CommandBindings.Add(UndoCommandBinding);

      CommandBinding RedoCommandBinding = new CommandBinding(ApplicationCommands.Redo);
      RedoCommandBinding.Executed += new ExecutedRoutedEventHandler(RedoCommandBinding_Executed);
      RedoCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(RedoCommandBinding_CanExecute);
      CommandBindings.Add(RedoCommandBinding);
    }

    public void AddWozScreen(WozScreen wozScreen)
    {
      wozScreen.CommandOccured += new SketchPad.CommandOccuredDelegate(WozScreen_CommandOccured);
      wozScreen.CommandOccuredNoUndoRedo += new SketchPad.CommandOccuredDelegate(wozScreen_CommandOccuredNoUndoRedo);
      wozScreen.ContinuousCommandOccured += new SketchPad.CommandOccuredDelegate(wozScreen_ContinuousCommandOccured);
      WozScreens.Add(wozScreen);
      if (_ScreensListBox != null)
      {
        _ScreensListBox.SelectedItem = wozScreen;
      }
    }

    void ScratchWindow_Loaded(object sender, RoutedEventArgs e)
    {
      _ToolSelectToolbar.WozServerCommandOccured += new WozLib.UI.Controls.ToolSelectToolbar.WozServerCommandOccuredDelegate(_ToolSelectToolbar_WozServerCommandOccured);
      _ScreensListBox.SelectionChanged += new SelectionChangedEventHandler(_ScreensListBox_SelectionChanged);
      _ScreensListBox.ItemsReordered += new RoutedEventHandler(_ScreensListBox_ItemsReordered);

      // should really use a routed command for this
      _AddScreenButton.Click += new RoutedEventHandler(_AddScreenButton_Click);
      _AddScreenButton2.Click += new RoutedEventHandler(_AddScreenButton_Click);
    }

    bool _undoingredoing = false;
    public void Undo()
    {
      if (_UndoStack.Count > 0)
      {
        _undoingredoing = true;
        WozLib.WozCommands.WozCommand wozServerCommand = _UndoStack.Pop();
        UndoWozCommand wozUndoCommand = new UndoWozCommand(wozServerCommand);
        WozServerCommandOccuredNoUndo(wozUndoCommand);
        wozServerCommand.Undo();
        _RedoStack.Push(wozServerCommand);

        _undoingredoing = false;
      }
    }

    public void Redo()
    {
      if (_RedoStack.Count > 0)
      {
        _undoingredoing = true;
        WozLib.WozCommands.WozCommand wozServerCommand = _RedoStack.Pop();
        RedoWozCommand wozRedoCommand = new RedoWozCommand(wozServerCommand);
        WozServerCommandOccuredNoUndo(wozRedoCommand);
        wozServerCommand.Redo();
        _UndoStack.Push(wozServerCommand);

        _undoingredoing = false;
      }
    }

    void RedoCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
      e.CanExecute = _RedoStack.Count > 0;
    }

    void RedoCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      Redo();
    }

    void UndoCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
      e.CanExecute = _UndoStack.Count > 0;
    }

    void UndoCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      Undo();
    }

    private void WozServerCommandOccured(WozLib.WozCommands.WozCommand wozServerCommand)
    {
      if (!_undoingredoing)
      {

        _WizardHistory.Add(wozServerCommand);
        _UndoStack.Push(wozServerCommand);
        _RedoStack.Clear();
      }
    }

    private void WozServerCommandOccuredNoUndo(WozLib.WozCommands.WozCommand wozServerCommand)
    {
      _WizardHistory.Add(wozServerCommand);
    }


    void _ScreensListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
      if (e.AddedItems.Count == 1 && e.RemovedItems.Count == 1 && e.AddedItems[0] is IServerObject && e.RemovedItems[0] is IServerObject)
      {

        WozScreenSelectCommand wozScreenSelectCommand = new WozScreenSelectCommand(this, (e.RemovedItems[0] as IServerObject).ServerID, (e.AddedItems[0] as IServerObject).ServerID);

        WozServerCommandOccured(wozScreenSelectCommand);
      }
    }

    void _ScreensListBox_ItemsReordered(object sender, RoutedEventArgs e)
    {
      try
      {
        int selectedIndex = _ScreensListBox.SelectedIndex;
        ((WozScreenCollection)_ScreensListBox.ItemsSource).Move(_ScreensListBox.OriginalItemIndex, selectedIndex);
        _ScreensListBox.SelectedIndex = selectedIndex;
      }
      catch (Exception ex)
      {
        Debug.WriteLine(ex.ToString());
      }
    }

    void _ToolSelectToolbar_WozServerCommandOccured(WozCommand wozServerCommand)
    {
      WozServerCommandOccured(wozServerCommand);
    }

    void _AddScreenButton_Click(object sender, RoutedEventArgs e)
    {
      AddScreen();
    }

    private void AddScreen()
    {
      try
      {
        double width = 1024;
        double height = 768;

        if (_ScreensListBox.Items.Count > 0 && _ScreensListBox.Items[0] is WozScreen)
        {
          width = (_ScreensListBox.Items[0] as WozScreen).Width;
          height = (_ScreensListBox.Items[0] as WozScreen).Height;
        }

        if (_ScreensListBox.SelectedItem is WozScreen)
        {
          width = (_ScreensListBox.SelectedItem as WozScreen).Width;
          height = (_ScreensListBox.SelectedItem as WozScreen).Height;
        }

        WozScreen wozScreen = new WozScreen(width, height);
        ServerObjectRegistry.RegisterObject(wozScreen);
        wozScreen.CommandOccured += new SketchPad.CommandOccuredDelegate(WozScreen_CommandOccured);
        wozScreen.CommandOccuredNoUndoRedo += new SketchPad.CommandOccuredDelegate(wozScreen_CommandOccuredNoUndoRedo);
        wozScreen.ContinuousCommandOccured += new SketchPad.CommandOccuredDelegate(wozScreen_ContinuousCommandOccured);
        WozScreens.Add(wozScreen);
        _ScreensListBox.SelectedItem = wozScreen;
        _ScreensListBox.ScrollIntoView(wozScreen);
        _ScreensListBox2.ScrollIntoView(wozScreen);
      }
      catch (Exception ex)
      {
        Debug.WriteLine("Add new screen failed: " + ex.ToString());
      }
    }

    void wozScreen_ContinuousCommandOccured(WozLib.WozCommands.WozCommand wozServerCommand)
    {

    }

    void wozScreen_CommandOccuredNoUndoRedo(WozCommand wozServerCommand)
    {
      ////hack
      if (wozServerCommand is WozLib.WozCommands.SelectToolWozCommand)
      {
        wozServerCommand.Redo();
      }

      WozServerCommandOccuredNoUndo(wozServerCommand);
    }

    void WozScreen_CommandOccured(WozLib.WozCommands.WozCommand wozServerCommand)
    {
      ////hack
      if (wozServerCommand is WozLib.WozCommands.SketchPadWozCommand &&
         (wozServerCommand as WozLib.WozCommands.SketchPadWozCommand).WozServerCommand is WozLib.WozCommands.SelectToolWozCommand)
      {
        wozServerCommand.Redo();
      }

      WozServerCommandOccured(wozServerCommand);
    }

    /// <summary>
    /// if the calling textbox is not focused, this method focuses the textbox
    /// and selects all the text. One would use this method as the PreviewMouseDown
    /// for textboxes where they want the user to just be able to type a new
    /// value after the textbox is clicked once.
    /// 
    /// We cannot use GotFocus because the click handler will unselect the text and
    /// place the cursor at the click point
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void _TextBox_SelectAll_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
      // if it was a textbox that was clicked and its not selected
      if (sender is TextBox && !(sender as TextBox).IsFocused)
      {
        // select all the text
        (sender as TextBox).SelectAll();

        // give the textbox input focus
        (sender as TextBox).Focus();

        // set handled to true to prevent the regular textbox click code from running
        e.Handled = true;
      }
    }

    /// <summary>
    /// this method focuses the textbox and selects all the text. 
    /// One would use this method as the GotFocus
    /// for textboxes where they want the user to just be able to type a new
    /// value after the textbox is tabbed into.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void _TextBox_SelectAll_GotFocus(object sender, RoutedEventArgs e)
    {
      if (sender is TextBox)
      {
        // select all the text
        (sender as TextBox).SelectAll();
      }
    }


    #region IServerObject Members

    public long ServerID
    {
      get
      {
        return _ServerID;
      }
      set
      {
        _ServerID = value;
      }
    } long _ServerID;

    public ServerObject GetServerObject()
    {
      return new ScratchWindowWozObject(ServerID);
    }

    #endregion
  }
}